package com.mini.framework.core;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.mini.framework.core.annotation.Autowired;
import com.mini.framework.core.annotation.Component;
import com.mini.framework.core.annotation.Controller;

public abstract class AbstractApplicationContext implements ApplicationContext {
	
	protected Map<String,Object> map ;
	
	private ApplicationBeanReader reader;
	
	
	
	public AbstractApplicationContext(){
		map = new HashMap<String,Object>();
		reader = new AnnotationBeanReader();
		try{
			load(null);
			inject();
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 加载.
	 * @param path
	 * @throws Exception
	 */
	private void load(String path) throws Exception{
		Set<Class<?>> classes = reader.getClasses(path);
		for(Class<?> c:classes){
			Object o = c.newInstance();
			Set<String> keySet = getInstanceMapKey(c);
			for(String key:keySet){
				map.put(key, o);
			}
			
			loadObject2Context(c,o);
		}
	}
	
	/**
	 * 注入.
	 * 
	 * @throws Exception
	 */
	private void inject() throws Exception{
		for(Object obj:map.values()){
			//属性注入.
			Field[] fs = obj.getClass().getDeclaredFields();
			for(Field field : fs){
				if(field.getAnnotation(Autowired.class) != null){
					field.setAccessible(true);
					Class<?> clazz = field.getType();
					String key = field.getAnnotation(Autowired.class).value();
					Object instance = map.get(key.length()>0?key:clazz.getName());
					field.set(obj, instance);
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <T> T getBean(String id) {
		return (T)map.get(id);
	}
	
	public Properties getConfigProperties(){
		return reader.getProperties();
	}
	
	
	
	private Set<String> getInstanceMapKey(Class<?> c){
		Set<String> mapKeySet = new LinkedHashSet<String>();
		mapKeySet.add(c.getName());
		
		String lastName = c.getName().substring(c.getName().lastIndexOf(".")+1);
		mapKeySet.add(lastName);
		mapKeySet.add(String.valueOf(lastName.charAt(0)).toLowerCase().concat(lastName.substring(1)));
		
		Class<?>[] cc = c.getInterfaces();
		for(Class<?> ccc:cc){
			mapKeySet.add(ccc.getName());
		}
		
		Component component = c.getAnnotation(Component.class);
		if(component != null && component.value().length()>0){
			mapKeySet.add(component.value());
		}
		Controller controller = c.getAnnotation(Controller.class);
		if(controller != null && controller.value().length()>0){
			mapKeySet.add(controller.value());
		}
		return mapKeySet;
	}
	
	

	public abstract void loadObject2Context(Class<?> c,Object o);
	
	
	

}
